﻿namespace EACProxy.Console
{
    using System;
    using System.Collections.Generic;

    using System.Text;
    using System.Net;
    using System.Net.Sockets;
    using System.IO;
    using WinEACProxy;

    /// <summary>
    /// Main proxy class to host a TCP listener that forwards on EAC requests
    /// as proper Http web requests to freedb. Does not handle multiple simultaneous requests.    
    /// </summary>
    public class Proxy
    {
        /// <summary>
        /// Port number to listen on
        /// </summary>
        public int Port { get; set; }

        /// <summary>
        /// Root URL of freedb.org to forward on to
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// Whether still running
        /// </summary>
        public volatile bool Running;

        /// <summary>
        /// Status events for progress or errors
        /// </summary>
        public event EventHandler<StatusEventArgs> Status;

        /// <summary>
        /// Log a new status event
        /// </summary>
        /// <param name="message"></param>
        private void Log(string message)
        {
            if (Status != null)
            { 
                Status(this, new StatusEventArgs() { Message = message });
            }
        }

        /// <summary>
        /// Main listen method that blocks on specified port
        /// </summary>
        public void Listen()
        {            
            TcpListener server = null;
            try
            {
                Int32 port = this.Port;
                IPAddress localAddr = IPAddress.Parse("127.0.0.1");

                // TcpListener server = new TcpListener(port);
                server = new TcpListener(localAddr, port);

                // Start listening for client requests.                
                Running = true;

                server.Start();             

                // Enter the listening loop.                
                while (Running)
                {
                    Log("Ready for EAC on port "+port);

                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();
                    Log("Connection received");                    

                    // Get a stream object for reading and writing
                    NetworkStream stream = client.GetStream();
                    StreamReader sr = new StreamReader(stream);
                    StringBuilder sb = new StringBuilder();
                    int c;
                    while ((c = sr.Read()) > 0)
                    {
                        sb.Append((char)c);
                        if (sb.ToString().IndexOf(" HTTP/1.") > 0)
                        {
                            break;
                        }
                    }
                    //stream.Write(msg, 0, msg.Length);
                    string responseString = MakeRequestToFreedb(sb.ToString());
                    System.Console.WriteLine(responseString);
                    byte[] response = System.Text.Encoding.UTF8.GetBytes(responseString);
                    stream.Write(response, 0, response.Length);

                    // Shutdown and end connection
                    client.Close();
                }
            }
            catch (SocketException e)
            {
                Log(string.Format("ERROR: SocketException: {0}", e.Message));
            }
            finally
            {
                // Stop listening for new clients.
                server.Stop();
            }
        }

        public string MakeRequestToFreedb(string request)
        {
            request = request.Substring(request.IndexOf("?"));
            request = request.Substring(0, request.Length - " HTTP/1.".Length);
            string freeDbReq = this.Url + request;
            Log("Connection received.. passing to freedb..");                    
            HttpWebRequest req = HttpWebRequest.Create(freeDbReq) as HttpWebRequest;
            HttpWebResponse response = req.GetResponse() as HttpWebResponse;

            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string responseString = sr.ReadToEnd();
                Log("Done");
                // EAC probably only cares about the 200 response code
                return @"HTTP/1.1 200 OK
Date: Wed, 04 Mar 2009 21:57:58 GMT
Server: Apache/2.0.54 (Debian GNU/Linux)
Expires: Wed Mar  4 22:57:58 2009
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/plain; charset=ISO-8859-1" + Environment.NewLine + responseString;
            }
        }
    }
}
